/*
  Copyright 2002-2003 The University of Texas at Austin
  
    Authors: Anthony Thane <thanea@ices.utexas.edu>
             Vinay Siddavanahalli <skvinay@cs.utexas.edu>
    Advisor: Chandrajit Bajaj <bajaj@cs.utexas.edu>

  This file is part of Volume Rover.

  Volume Rover is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  Volume Rover is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with iotree; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "ColorTable.h"
#include <qlayout.h>

//using namespace PBVP;

ColorTable::ColorTable( QWidget *parent, const char *name )
: QFrame( parent)
{
	setFrameStyle( QFrame::Panel | QFrame::Raised );

	QBoxLayout *layout = new QBoxLayout(QBoxLayout::Down, this);
	layout->setMargin( 3 );
	layout->setSpacing( 3 );

	m_XoomedIn = new XoomedIn( &m_TransferMap, this, "Xoomed In");
	m_XoomedOut = new XoomedOut( &m_TransferMap, m_XoomedIn, this, "Xoomed Out" );

	layout->addWidget( m_XoomedOut );
	layout->addWidget( m_XoomedIn );
	m_XoomedOut->setFixedHeight( 20 );

	// connect the signals and slots
	connect(m_XoomedIn, SIGNAL(isocontourNodeChanged(int, double, double,double,double)), this, SLOT(relayIsocontourNodeChanged(int, double, double,double,double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeColorChanged(int, double,double,double)), this, SLOT(relayIsocontourNodeColorChanged(int, double,double,double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeExploring(int, double)), this, SLOT(relayIsocontourNodeExploring(int, double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeAdded(int, double,double,double,double)), this, SLOT(relayIsocontourNodeAdded(int, double,double,double,double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeDeleted(int)),  this, SLOT(relayIsocontourNodeDeleted(int)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeSaved(int)),  this, SLOT(relayIsocontourNodeSaved(int)));

	connect(m_XoomedIn, SIGNAL(functionChanged()),  this, SLOT(relayFunctionChanged()));
	connect(m_XoomedIn, SIGNAL(functionExploring()),  this, SLOT(relayFunctionExploring()));

	connect(m_XoomedIn, SIGNAL(everythingChanged()), this, SLOT(relayEverythingChanged()));
	
	connect(m_XoomedIn, SIGNAL(acquireContourSpectrum()), this, SLOT(relayAcquireContourSpectrum()));
	connect(m_XoomedIn, SIGNAL(acquireContourTree()), this, SLOT(relayAcquireContourTree()));

	connect(m_XoomedIn, SIGNAL(selectedColorNode()), this, SLOT(relaySelectedColorNode()));
	connect(m_XoomedIn, SIGNAL(selectedIsocontourNode(int, double)), this, SLOT(relaySelectedIsocontourNode(int, double)));
	connect(m_XoomedIn, SIGNAL(selectedAlphaNode()), this, SLOT(relaySelectedAlphaNode()));

	connect(this, SIGNAL(spectrumFunctionsChanged(float*,float*,float*,float*,float*)), m_XoomedIn, SLOT(setSpectrumFunctions(float*,float*,float*,float*,float*)));
//	connect(this, SIGNAL(contourTreeChanged(int,int,CTVTX*,CTEDGE*)), m_XoomedIn, SLOT(setCTGraph(int,int,CTVTX*,CTEDGE*)));

}

ColorTable::ColorTable()
: QFrame()
{
	setFrameStyle( QFrame::Panel | QFrame::Raised );

	QBoxLayout *layout = new QBoxLayout( QBoxLayout::Down, this );
	layout->setMargin( 3 );
	layout->setSpacing( 3 );

	m_XoomedIn = new XoomedIn( &m_TransferMap, this, "Xoomed In" );
	m_XoomedOut = new XoomedOut( &m_TransferMap, m_XoomedIn, this, "Xoomed Out" );

	layout->addWidget( m_XoomedOut );
	layout->addWidget( m_XoomedIn );
	m_XoomedOut->setFixedHeight( 20 );

	// connect the signals and slots
	connect(m_XoomedIn, SIGNAL(isocontourNodeChanged(int, double, double,double,double)), this, SLOT(relayIsocontourNodeChanged(int, double, double,double,double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeColorChanged(int, double,double,double)), this, SLOT(relayIsocontourNodeColorChanged(int, double,double,double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeExploring(int, double)), this, SLOT(relayIsocontourNodeExploring(int, double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeAdded(int, double,double,double,double)), this, SLOT(relayIsocontourNodeAdded(int, double,double,double,double)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeDeleted(int)),  this, SLOT(relayIsocontourNodeDeleted(int)));
	connect(m_XoomedIn, SIGNAL(isocontourNodeSaved(int)),  this, SLOT(relayIsocontourNodeSaved(int)));

	connect(m_XoomedIn, SIGNAL(functionChanged()),  this, SLOT(relayFunctionChanged()));
	connect(m_XoomedIn, SIGNAL(functionExploring()),  this, SLOT(relayFunctionExploring()));

	connect(m_XoomedIn, SIGNAL(everythingChanged()), this, SLOT(relayEverythingChanged()));
	
	connect(m_XoomedIn, SIGNAL(acquireContourSpectrum()), this, SLOT(relayAcquireContourSpectrum()));
	connect(m_XoomedIn, SIGNAL(acquireContourTree()), this, SLOT(relayAcquireContourTree()));

	connect(m_XoomedIn, SIGNAL(selectedColorNode()), this, SLOT(relaySelectedColorNode()));
	connect(m_XoomedIn, SIGNAL(selectedIsocontourNode()), this, SLOT(relaySelectedIsocontourNode()));
	connect(m_XoomedIn, SIGNAL(selectedAlphaNode()), this, SLOT(relaySelectedAlphaNode()));

	connect(this, SIGNAL(spectrumFunctionsChanged(float*,float*,float*,float*,float*)), m_XoomedIn, SLOT(setSpectrumFunctions(float*,float*,float*,float*,float*)));
//	connect(this, SIGNAL(contourTreeChanged(int,int,CTVTX*,CTEDGE*)), m_XoomedIn, SLOT(setCTGraph(int,int,CTVTX*,CTEDGE*)));

}

ColorTable::~ColorTable()
{

}

int ColorTable::MapToPixel(float input, int start, int end)
{
	if (input <= 1.0 && input >= 0.0) {
		int width = end-start;
		int offset = (int)(input * width);
		return start + offset;
	}
	else if (input > 1.0) {
		return end;
	}
	else {
		return start;
	}
}

double ColorTable::MapToDouble(int input, int start, int end)
{
	int width = end-start;
	int offset = input-start;

	return (double)offset/(double)width;
}

void ColorTable::GetTransferFunction(double *pMap, int size)
{
	double mag;
	int pos1, pos2;
	double cr1, cr2;
	double cg1, cg2;
	double cb1, cb2;
	double alpha1, alpha2;

	int mapSize = m_TransferMap.getColorMap().size();
	int i;
	for (i=0; i<mapSize-1; i++) {
		pos1 = MapToPixel(m_TransferMap.getColorMap().GetPosition(i), 0, size-1);
		pos2 = MapToPixel(m_TransferMap.getColorMap().GetPosition(i+1), 0, size-1);
		cr1 = m_TransferMap.getColorMap().GetRed(i);
		cr2 = m_TransferMap.getColorMap().GetRed(i+1);
		cg1 = m_TransferMap.getColorMap().GetGreen(i);
		cg2 = m_TransferMap.getColorMap().GetGreen(i+1);
		cb1 = m_TransferMap.getColorMap().GetBlue(i);
		cb2 = m_TransferMap.getColorMap().GetBlue(i+1);
		for (int y=pos1; y<=pos2; y++) {
			mag = MapToDouble(y, pos1, pos2);
			pMap[y*4] = cr1*(1.0f-mag) + cr2*(mag);
			pMap[y*4+1] = cg1*(1.0f-mag) + cg2*(mag);
			pMap[y*4+2] = cb1*(1.0f-mag) + cb2*(mag);
		}
	}
	mapSize = m_TransferMap.getAlphaMap().size();
	for (i=0; i<mapSize-1; i++) {
		pos1 = MapToPixel(m_TransferMap.getAlphaMap().GetPosition(i), 0, size-1);
		pos2 = MapToPixel(m_TransferMap.getAlphaMap().GetPosition(i+1), 0, size-1);
		alpha1 = m_TransferMap.getAlphaMap().GetAlpha(i+0);
		alpha2 = m_TransferMap.getAlphaMap().GetAlpha(i+1);
		//alpha1 = MapToPixel(m_ColorTableInformation.getAlphaMap().GetAlpha(i), 0, 255);
		//alpha2 = MapToPixel(m_ColorTableInformation.getAlphaMap().GetAlpha(i+1), 0, 255);
		for (int y=pos1; y<=pos2; y++) {
			mag = MapToDouble(y, pos1, pos2);
			pMap[y*4+3] = alpha1*(1.0f-mag) + alpha2*(mag);
		}
	}
}

QSize ColorTable::sizeHint() const
{
	return QSize(150, 150);
}

TransferMap ColorTable::getColorTableInformation()
{
	return TransferMap(m_TransferMap);
}

const IsocontourMap& ColorTable::getIsocontourMap() const
{
	return m_TransferMap.getIsocontourMap();
}

void ColorTable::setSpectrumFunctions(float *isoval, float *area, float *min_vol, float *max_vol, float *gradient)
{
	emit spectrumFunctionsChanged(isoval,area,min_vol,max_vol,gradient);
}

/*void ColorTable::setContourTree(int numVerts, int numEdges, CTVTX *verts, CTEDGE *edges)
{
	emit contourTreeChanged(numVerts,numEdges,verts,edges);
}*/

void ColorTable::relayIsocontourNodeChanged( int index, double isovalue, double R, double G, double B )
{
	emit isocontourNodeChanged(index, isovalue, R, G, B );
}

void ColorTable::relayIsocontourNodeColorChanged( int index, double R, double G, double B )
{
	emit isocontourNodeColorChanged(index, R,G,B);
}

void ColorTable::relayIsocontourNodeExploring( int index, double isovalue )
{
	emit isocontourNodeExploring(index, isovalue);
}

void ColorTable::relayIsocontourNodeAdded( int index, double isovalue, double R, double G, double B )
{
	emit isocontourNodeAdded(index, isovalue, R,G,B);
}

void ColorTable::relayIsocontourNodeDeleted( int index )
{
	emit isocontourNodeDeleted(index);
}

void ColorTable::relayIsocontourNodeSaved( int index )
{
	emit isocontourNodeSaved(index);
}

void ColorTable::relayFunctionChanged( )
{
	m_XoomedOut->repaint();
	emit functionChanged();
}

void ColorTable::relayFunctionExploring( )
{
	m_XoomedOut->repaint();
	emit functionExploring();
}


void ColorTable::relayAcquireContourSpectrum()
{
	emit acquireContourSpectrum();
}

void ColorTable::relayAcquireContourTree()
{
	emit acquireContourTree();
}


void ColorTable::relayEverythingChanged()
{
	m_XoomedOut->repaint();
	emit everythingChanged();
}

void ColorTable::setValExtents( double minVal, double maxVal )
{
	if( m_XoomedIn )
	{
		m_XoomedIn->setValExtents( minVal, maxVal );
	}
}

bool ColorTable::removeIsocontourBar(int index)
{
	return m_XoomedIn->removeIsocontourBar( index );
}

void ColorTable::relaySelectedColorNode()
{
	emit selectedColorNode(); 
}

void ColorTable::relaySelectedIsocontourNode(int index, double isovalue)
{
	emit selectedIsocontourNode( index, isovalue );
}

void ColorTable::relaySelectedAlphaNode()
{
	emit selectedAlphaNode();
}

bool ColorTable::removeSandwichedNodes()
{
	m_TransferMap.removeSandwichedNodes();
	return true;
}

void ColorTable::resetNodes()
{
	m_TransferMap.resetNodes();
	m_XoomedIn->setDrawAlphaMap( false );
}

void ColorTable::loadMap(const QString &fname)
{
	printf("load colormap %s\n", fname.toAscii().data());
	m_XoomedIn->loadMap(fname);
}